<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Fiber - 第一阶段：render阶段</title>
    <!-- 加载React库 -->
    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <!-- 加载Babel编译器 -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">
      const jsx = (
         <div id="a1">
          <div id="b1">
            <div id="c1"></div>
            <div id="c2"></div>
          </div>
          <div id="b2"></div>
        </div>
      )

      // 获取挂载的根节点
      const container = document.getElementById("root")

      // 1. 构建根Fiber: stateNode => fiber对象所对应的DOM对象
      const workInProgressRoot = {
      	stateNode: container,
      	props: {children: [jsx]}
      }

      // 2. 开始第一阶段：render阶段 => 通过循环（模拟递归）来构建子元素的fiber对象
      let nextUnitOfWork = workInProgressRoot // 存储接下来执行的任务
      function workLoop(deadline) {
      	// 循环条件：①是否在浏览器空闲时间 ②是否还存在需要执行的任务
      	while(deadline.timeRemaining() > 0 && nextUnitOfWork) {
      		nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
      	}
      	if(!nextUnitOfWork) {
      		// 任务均执行完成，无接下来的任务 => 进入第二阶段 commit
      		commitRoot()
      	}
      }

      // 3. fiber的构建需要在浏览器闲时执行
      requestIdleCallback(workLoop)

      // 4. 处理单个任务
      function performUnitOfWork(workInProgressFiber) {
      	// 构建单个fiber: ①创建DOM对象并存储在stateNode属性中,设置DOM的props ②构建当前fiber的子集fiber
      	beginWork(workInProgressFiber)

      	// wookLoop中执行performUnitOfWork结束后需要返回下一个需要处理的fiber
      	if(workInProgressFiber.child) return workInProgressFiber.child
      }

      // 5. 构建单个fiber任务
      function beginWork(workInProgressFiber) {
      	// ①创建DOM对象并存储在stateNode属性中,设置DOM的props,其中RootFiber不需要此构建
      	if(!workInProgressFiber.stateNode) {
      		workInProgressFiber.stateNode = document.createElement(workInProgressFiber.type)
      		for(let attr in workInProgressFiber.props) {
      			if(attr !== "children") {
      				workInProgressFiber.stateNode[attr] = workInProgressFiber.props[attr]
      			}
      		}
      	}
      	// ②构建当前fiber的子集fiber,
      	if(Array.isArray(workInProgressFiber.props.children)) {
      		// 存储本次循环中的上一个fiber
      		let previousFiber = null
      		workInProgressFiber.props.children.forEach((child, index) => {
      			// fiber的链表结构：父级节点是谁，子级节点是谁，以及下一个兄弟节点是谁（这样才能知道下一个fiber任务是谁）
      			let childFiber = {
      				type: child.type,
      				props: child.props,
      				effectTag: "PLACEMENT", // 表示fiber当前执行DOM操作
      				return: workInProgressFiber // 父层fiber
      			}
      			if(index === 0) {
      			  // children的第一项作为workInProgressFiber的子级节点
      				workInProgressFiber.child = childFiber
      			} else {
      				// 其他项作为上一个fiber的兄弟节点
      				previousFiber.sibling = childFiber
      			}
      			// 记录本次循环中的上一个fiber
      			previousFiber = childFiber
      		})
      	}

        console.log('workInProgressFiber:')
      	console.log(workInProgressFiber)
      }

      // 开始第二阶段：commit
      function commitRoot() {
        console.log('Fiber Tree')
        console.log(workInProgressRoot)
      }
    </script>
  </body>
</html>
